﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WpfRcp.Core.Services.Commands;
using WpfRcp.Core.Common;
using System.Windows;
using Microsoft.Practices.Composite.Regions;
using WpfRcp.Core.Common.Extensions;
using WpfRcp.Core.Globals;

namespace WpfRcp.Services.Commands
{
    public class MenuRegistry : IMenuRegistry
    {
        private bool m_IsRunning;
        protected readonly IRegionManager m_RegionManager;
        protected readonly IMenuItemFactory m_Factory;

        private readonly IMenuItemCollection m_MenuItems;
        private readonly IMenuItemGroupCollection m_MenuItemGroups;

        private readonly IMenuItemTabCollection m_MenuTabs;

        private readonly IActionRegistry m_actionRegistry;

        public MenuRegistry(IRegionManager regionManager, IActionRegistry actionRegistry, IMenuItemFactory factory)
        {
            m_RegionManager = regionManager;
            m_Factory = factory;

            m_actionRegistry = actionRegistry;
            m_MenuItems = new MenuItemCollection(m_actionRegistry, this);
            m_MenuItemGroups = new MenuItemGroupCollection();
            m_MenuTabs = new MenuItemTabCollection();

            MenuItemGroups.CollectionChanged += (sender, e) => m_MenuItems.UpdatePendingItems();
            m_actionRegistry.CommandDescriptors.CollectionChanged += (sender, e) => m_MenuItems.UpdatePendingItems();
        }

        public IMenuItemTabCollection MenuItemTabs
        {
            get { return m_MenuTabs; }
        }

        public IMenuItemGroupCollection MenuItemGroups
        {
            get { return m_MenuItemGroups; }
        }

        public IMenuItemCollection MenuItems
        {
            get { return m_MenuItems; }
        }

        public IMenuTab RegisterMenuTab(string name)
        {
            if (m_MenuTabs.ContainsItemWithName(name))
            {
                return m_MenuTabs[name];
            }

            IMenuTab tab = new MenuTab(name);
            m_MenuTabs.Add(tab);

            return tab;
        }

        public IMenuItemGroup RegisterMenuItemGroup(string name, string tabName)
        {
            if (m_MenuItemGroups.ContainsItemWithName(name))
                return m_MenuItemGroups[name];

            IMenuItemGroup group = new MenuItemGroup(name, m_MenuTabs[tabName]);
            m_MenuItemGroups.Add(group);

            return group;
        }

        private static int i = 0;
        public IMenuItem RegisterMenuItem(string name, string groupName, string commandName)
        {
            return RegisterMenuItem(name, groupName, commandName, null);
        }

        public IMenuItem RegisterMenuItem(string name, string groupName, string commandName, object icon)
        {
            if (m_MenuItems.ContainsItemWithName(name))
            {
                return m_MenuItems[name];
            }

            if (string.IsNullOrEmpty(groupName) || !m_MenuItemGroups.ContainsItemWithName(groupName)
                || (!string.IsNullOrEmpty(commandName) && !m_actionRegistry.CommandDescriptors.ContainsItemWithName(commandName)))
            {
                throw new ArgumentException();
            }

            ICommandDescriptor command = string.IsNullOrEmpty(commandName) ? null : m_actionRegistry.CommandDescriptors[commandName];
            IMenuItemGroup group = m_MenuItemGroups[groupName];

            IMenuItem menuItem = new MenuItem(name) { Group = group, Command = command, Icon = icon};
            m_MenuItems.Add(menuItem);

            return menuItem;
        }

        public void Run()
        {
            if (m_IsRunning)
                throw new InvalidOperationException("Service already running.");

            m_IsRunning = true;

            var tabs = from tab in m_MenuTabs
                       orderby tab.Position
                       select tab;

            foreach (var tab in tabs)
            {
                ProcessTab(tab);
            }
        }

        private void ProcessTab(IMenuTab tab)
        {
            var visualTab = m_Factory.GetVisualTab(tab);
            tab.Visual = visualTab;

            if (m_RegionManager.Regions.ContainsRegionWithName(RegionNames.MainMenuRegion))
            {
                m_RegionManager.Regions[RegionNames.MainMenuRegion].Add(visualTab);
                m_RegionManager.AttachNewRegion(visualTab, tab.Name);

                var groups = from @group in m_MenuItemGroups
                             where @group.MenuTab == tab
                             orderby @group.Position
                             select @group;

                foreach (var @group in groups)
                {
                    ProcessGroup(@group);
                }
            }
        }

        private void ProcessGroup(IMenuItemGroup menuItemGroup)
        {
            var items = from item in m_MenuItems
                        where item.Group == menuItemGroup
                        orderby item.Position
                        select item;

            foreach (var item in items)
            {
                ProcessItem(item);
            }
        }

        private void ProcessItem(IMenuItem item)
        {
            var visualItem = m_Factory.GetVisualItem(item);
            item.Visual = visualItem;

            string regionName = item.Group.MenuTab.Name;

            GroupingViewsCollection.SetGroupIndex(visualItem, item.Group.Position);
            GroupingViewsCollection.SetGroupName(visualItem, item.Group.Name);
            GroupingViewsCollection.SetGroupText(visualItem, item.Group.Text);
            GroupingViewsCollection.SetRegion(visualItem, m_RegionManager.Regions[regionName]);

            if (m_RegionManager.Regions.ContainsRegionWithName(regionName))
            {
                m_RegionManager.Regions[regionName].Add(visualItem);
                m_RegionManager.AttachNewRegion(visualItem, item.Name);
            }
        }
    }

    #region MenuItemCollection

    public class MenuItemCollection : WpfRcp.Services.Commands.ActionRegistry.ItemCollectionBase<IMenuItem>, IMenuItemCollection
    {
        private readonly IActionRegistry m_ActionRegistry;
        private readonly IMenuRegistry m_menuRegistry;

        public MenuItemCollection(IActionRegistry actionRegistry, IMenuRegistry menuRegistry)
        {
            m_ActionRegistry = actionRegistry;
            m_menuRegistry = menuRegistry;
        }
    }

    #endregion

    #region MenuItemGroupCollection

    public class MenuItemGroupCollection : WpfRcp.Services.Commands.ActionRegistry.ItemCollectionBase<IMenuItemGroup>, IMenuItemGroupCollection
    {
    }

    public class MenuItemTabCollection : WpfRcp.Services.Commands.ActionRegistry.ItemCollectionBase<IMenuTab>, IMenuItemTabCollection
    {
    }

    #endregion

}
